//*******************************************************************************
// COPYRIGHT NOTES
// ---------------
// This is a sample for BCGControlBar Library Professional Edition
// Copyright (C) 1998-2016 BCGSoft Ltd.
// All rights reserved.
//
// This source code can be used, distributed or modified
// only under terms and conditions 
// of the accompanying license agreement.
//*******************************************************************************
//
// ChartAdvancedLegendView.cpp : implementation file
//

#include "stdafx.h"
#include "bcgpchartexample.h"
#include "ChartAdvancedLegendView.h"
#include "MainFrm.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

///////////////////////////////////////////////////////////////////////////////
// Custom legend cells:

class CChartLegendControl : public CBCGPChartLegendCell
{
public:
	DECLARE_DYNAMIC(CChartLegendControl);
	
	CChartLegendControl(CChartAdvancedLegendView* pView, const CString& strName, BOOL bIsSelected) :
		CBCGPChartLegendCell(strName)
	{
		m_pView = pView;
		m_bIsSelected = bIsSelected;
	}

	void SetSelected(BOOL bSet)
	{
		m_bIsSelected = bSet;
		Redraw();
	}

	BOOL IsSelected() const
	{
		return m_bIsSelected;
	}
	
	virtual CBCGPSize OnCalcCustomCellSize(CBCGPGraphicsManager* pGM)
	{
		CBCGPSize size = CBCGPChartLegendCell::OnCalcCustomCellSize(pGM);
		
		size.cy += 4;
		size.cx += size.cy + size.cy / 4.0;
		
		return size;
	}
	
	virtual void OnDrawCheckRadio(CBCGPGraphicsManager* pGM, const CBCGPRect& rect, const CBCGPColor& color) = 0;
	
	virtual void OnDrawCustomCell(CBCGPGraphicsManager* pGM, const CBCGPRect& rect)
	{
		CBCGPRect rectCheck = rect;
		rectCheck.right = rectCheck.left + rectCheck.Height();
		
		CBCGPRect rectLabel = rect;
		rectLabel.left = rectCheck.right + rectCheck.Height() / 4.0;
		
		rectCheck.DeflateRect(2, 2);
		
		OnDrawCheckRadio(pGM, rectCheck, m_cellParams.m_brTextColor.GetColor());
		
		CBCGPChartLegendCell::OnDrawCustomCell(pGM, rectLabel);
	}
	
protected:
	BOOL						m_bIsSelected;
	CChartAdvancedLegendView*	m_pView;
};


class CChartLegendCheckBox : public CChartLegendControl
{
public:
	DECLARE_DYNAMIC(CChartLegendCheckBox);

	CChartLegendCheckBox(CChartAdvancedLegendView* pView, const CString& strName, BOOL bIsChecked) :
		CChartLegendControl(pView, strName, bIsChecked)
	{
	}

	virtual void OnMouseUp(const CBCGPPoint& pt)
	{
		ASSERT_VALID(m_pView);

		CBCGPChartLegendCell::OnMouseUp(pt);
		m_pView->OnLegendCheckBoxClicked(this);
	}

	virtual void OnDrawCheckRadio(CBCGPGraphicsManager* pGM, const CBCGPRect& rect, const CBCGPColor& color)
	{
		pGM->DrawCheckBox(rect, m_bIsSelected, color);
	}
};

class CChartLegendRadioButton : public CChartLegendControl
{
public:
	DECLARE_DYNAMIC(CChartLegendRadioButton);
	
	CChartLegendRadioButton(CChartAdvancedLegendView* pView, const CString& strName, BOOL bIsChecked) :
		CChartLegendControl(pView, strName, bIsChecked)
	{
	}
	
	virtual void OnMouseUp(const CBCGPPoint& pt)
	{
		ASSERT_VALID(m_pView);

		CBCGPChartLegendCell::OnMouseUp(pt);
		m_pView->OnLegendRadioButtonClicked(this);
	}
	
	virtual void OnDrawCheckRadio(CBCGPGraphicsManager* pGM, const CBCGPRect& rect, const CBCGPColor& color)
	{
		pGM->DrawRadioButton(rect, m_bIsSelected, color);
	}
};


IMPLEMENT_DYNAMIC(CChartLegendControl, CBCGPChartLegendCell)
IMPLEMENT_DYNAMIC(CChartLegendCheckBox, CChartLegendControl)
IMPLEMENT_DYNAMIC(CChartLegendRadioButton, CChartLegendControl)

/////////////////////////////////////////////////////////////////////////////
// CChartAdvancedLegendView form

IMPLEMENT_DYNCREATE(CChartAdvancedLegendView, CBCGPChartExampleView)

CChartAdvancedLegendView::CChartAdvancedLegendView()
	: CBCGPChartExampleView(CChartAdvancedLegendView::IDD)
{
	//{{AFX_DATA_INIT(CChartAdvancedLegendView)
	m_nHorzAlignment = 1;
	m_strLegendName = _T("Legend Title:");
	m_bShowChartNameInLegend = TRUE;
	m_bShowChart1 = TRUE;
	m_bShowChart2 = TRUE;
	m_bShowLegendTitle = TRUE;
	m_nVerticalAlignment = 1;
	m_bIsVerticalLayout = TRUE;
	m_bCustomEntries = TRUE;
	m_bShowGridLines = TRUE;
	//}}AFX_DATA_INIT

	m_pChart1 = NULL;
	m_pChart2 = NULL;
	m_pLegend = NULL;

	m_pCheck1 = NULL;
	m_pRadio1 = NULL;
	m_pRadio2 = NULL;

	m_bIsChecked = TRUE;
	m_nOption = 0;

	m_brCustomCellBackground = CBCGPBrush(CBCGPColor::LightSalmon, CBCGPColor::Wheat, CBCGPBrush::BCGP_GRADIENT_PIPE_HORIZONTAL);
	m_brCustomCellText = CBCGPBrush(CBCGPColor::DarkRed);
}


void CChartAdvancedLegendView::DoDataExchange(CDataExchange* pDX)
{
	CBCGPChartExampleView::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CChartAdvancedLegendView)
	DDX_Control(pDX, IDC_CUSTOM_ENTRIES, m_wndCustomEntries);
	DDX_Control(pDX, IDC_CHART, m_wndContainer);
	DDX_Control(pDX, IDC_LEGEND_NAME, m_wndLegendName);
	DDX_CBIndex(pDX, IDC_HORIZONTAL_ALIGNMENT, m_nHorzAlignment);
	DDX_Text(pDX, IDC_LEGEND_NAME, m_strLegendName);
	DDX_Check(pDX, IDC_SHOW_CHART_NAME_IN_LEGEND, m_bShowChartNameInLegend);
	DDX_Check(pDX, IDC_SHOW_CHART1, m_bShowChart1);
	DDX_Check(pDX, IDC_SHOW_CHART2, m_bShowChart2);
	DDX_Check(pDX, IDC_SHOW_LEGEND_TITLE, m_bShowLegendTitle);
	DDX_CBIndex(pDX, IDC_VERTICAL_ALIGNMENT, m_nVerticalAlignment);
	DDX_Check(pDX, IDC_VERTICAL_LAYOUT, m_bIsVerticalLayout);
	DDX_Check(pDX, IDC_CUSTOM_ENTRIES, m_bCustomEntries);
	DDX_Check(pDX, IDC_SHOW_GRID_LINES, m_bShowGridLines);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CChartAdvancedLegendView, CBCGPChartExampleView)
	//{{AFX_MSG_MAP(CChartAdvancedLegendView)
	ON_BN_CLICKED(IDC_SHOW_CHART1, OnUpdate)
	ON_EN_UPDATE(IDC_LEGEND_NAME, OnUpdateLegendName)
	ON_WM_SIZE()
	ON_BN_CLICKED(IDC_SHOW_CHART2, OnUpdate)
	ON_BN_CLICKED(IDC_CUSTOM_ENTRIES, OnUpdate)
	ON_BN_CLICKED(IDC_SHOW_LEGEND_TITLE, OnUpdate)
	ON_CBN_SELENDOK(IDC_VERTICAL_ALIGNMENT, OnUpdate)
	ON_CBN_SELENDOK(IDC_HORIZONTAL_ALIGNMENT, OnUpdate)
	ON_BN_CLICKED(IDC_VERTICAL_LAYOUT, OnUpdate)
	ON_BN_CLICKED(IDC_SHOW_CHART_NAME_IN_LEGEND, OnUpdate)
	ON_BN_CLICKED(IDC_SHOW_GRID_LINES, OnUpdate)
	//}}AFX_MSG_MAP
	ON_REGISTERED_MESSAGE(BCGM_ON_CHART_LEGEND_CONTENT_CREATED, OnLegendContentCreated)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CChartAdvancedLegendView message handlers

void CChartAdvancedLegendView::OnInitialUpdate() 
{
	CBCGPChartExampleView::OnInitialUpdate();

	if (m_bIsReady)
	{
		return;
	}
	
	CBCGPVisualContainer* pContainer = m_wndContainer.GetVisualContainer();
	ASSERT_VALID(pContainer);

	// Setup first chart:
	m_pChart1 = new CBCGPChartVisualObject(pContainer);
	ASSERT_VALID(m_pChart1);

	m_pChart1->SetChartTitle(_T("1-st Chart"));

	CBCGPChartSeries* pSeries1 = m_pChart1->CreateSeries(_T("Series 1"));
	CBCGPChartSeries* pSeries2 = m_pChart1->CreateSeries(_T("Series 2"));

	pSeries1->AddDataPoint(1.);
	pSeries1->AddDataPoint(2.);
	pSeries1->AddDataPoint(3.);
	pSeries1->AddDataPoint(2.);
	pSeries1->AddDataPoint(4.);
	
	pSeries2->AddDataPoint(3.);
	pSeries2->AddDataPoint(4.);
	pSeries2->AddDataPoint(6.);
	pSeries2->AddDataPoint(3.);
	pSeries2->AddDataPoint(8.);

	m_pChart1->ShowDataMarkers(TRUE, -1, BCGPChartMarkerOptions::MS_RHOMBUS);

	// Setup second chart:
	m_pChart2 = new CBCGPChartVisualObject(pContainer);
	ASSERT_VALID(m_pChart2);

	m_pChart2->SetChartTitle(_T("2-nd Chart"));

	m_pChart2->SetChartType(BCGPChartDoughnut);

	m_pChart2->AddChartData(_T("A1"), 10);
	m_pChart2->AddChartData(_T("A2"), 20);
	m_pChart2->AddChartData(_T("A3"), 30);
	m_pChart2->AddChartData(_T("A4"), 20);
	m_pChart2->AddChartData(_T("A5"), 15);

	// Setup legend:
	m_pLegend = new CBCGPChartLegendVisualObject(pContainer);
	ASSERT_VALID(m_pLegend);

	OnUpdate();
	Repos();
	
	CMainFrame* pMainFrame = (CMainFrame*)AfxGetMainWnd();
	UpdateChartColorTheme(pMainFrame->GetColorTheme(), pMainFrame->IsDarkTheme());

	m_bIsReady = TRUE;
}

void CChartAdvancedLegendView::UpdateChartColorTheme(int nTheme, BOOL bIsDarkTheme)
{
	if (m_pChart1 == NULL || m_pChart2 == NULL)
	{
		return;
	}

	CBCGPBrush brFill;

	if (nTheme < 0)
	{
		if (m_bIsDarkBackground)
		{
			m_bIsDarkBackground = FALSE;
			OnChangeBackgroundDarkness();
		}
		
		m_pChart1->SetColors(theApp.GetCustomTheme(nTheme), bIsDarkTheme);
		m_pChart2->SetColors(theApp.GetCustomTheme(nTheme), bIsDarkTheme);

		m_bIsTexturedTheme = nTheme == -1;
		m_bIsFlatTheme = FALSE;
		brFill = theApp.GetCustomTheme(nTheme).m_brChartFillColor;
	}
	else
	{
		CBCGPChartTheme::ChartTheme theme = (CBCGPChartTheme::ChartTheme)nTheme;
		
		BOOL bIsDarkBackground = FALSE;
		
		switch (theme)
		{
		case CBCGPChartTheme::CT_BLACK_AND_GOLD:
		case CBCGPChartTheme::CT_BLACK_AND_RED:
		case CBCGPChartTheme::CT_BLACK_AND_GREEN:
		case CBCGPChartTheme::CT_BLACK_AND_BLUE:
			bIsDarkBackground = TRUE;
			break;
		}
		
		if (m_bIsDarkBackground != bIsDarkBackground)
		{
			m_bIsDarkBackground = bIsDarkBackground;
			OnChangeBackgroundDarkness();
		}
		
		m_pChart1->SetColors((CBCGPChartTheme::ChartTheme)nTheme, bIsDarkTheme);
		m_pChart2->SetColors((CBCGPChartTheme::ChartTheme)nTheme, bIsDarkTheme);

		m_bIsTexturedTheme = FALSE;
		m_bIsFlatTheme = theme >= CBCGPChartTheme::CT_FLAT_2014_1 && theme <= CBCGPChartTheme::CT_FLAT_2016_5;

		brFill = m_pChart1->GetColors().m_brChartFillColor;
	}

	m_wndContainer.GetVisualContainer()->SetFillBrush(brFill);
}

void CChartAdvancedLegendView::OnUpdate() 
{
	ASSERT_VALID(m_pChart1);
	ASSERT_VALID(m_pChart2);
	ASSERT_VALID(m_pLegend);

	UpdateData();
	
	if (m_bShowChart1)
	{
		m_pLegend->AddRelatedChart(m_pChart1);
	}
	else
	{
		m_pLegend->RemoveRelatedChart(m_pChart1);
	}

	if (m_bShowChart2)
	{
		m_pLegend->AddRelatedChart(m_pChart2);
	}
	else
	{
		m_pLegend->RemoveRelatedChart(m_pChart2);
	}

	m_wndCustomEntries.EnableWindow(m_bShowChart1 || m_bShowChart2);

	m_wndLegendName.EnableWindow(m_bShowLegendTitle);

	m_pLegend->ShowChartNameInLegend(m_bShowChartNameInLegend);

	m_pLegend->SetVerticalAlignment((CBCGPChartLegendVisualObject::LegendAlignment)m_nVerticalAlignment);
	m_pLegend->SetHorizontalAlignment((CBCGPChartLegendVisualObject::LegendAlignment)m_nHorzAlignment);
	m_pLegend->SetVerticalLayout(m_bIsVerticalLayout);

	m_pLegend->m_legendStyle.m_bDrawHorizontalGridLines = m_pLegend->m_legendStyle.m_bDrawVerticalGridLines = m_bShowGridLines;

	m_pLegend->ShowLegendTitle(m_bShowLegendTitle, m_strLegendName);

	Repos();
}

void CChartAdvancedLegendView::OnUpdateLegendName() 
{
	UpdateData();

	ASSERT_VALID(m_pLegend);
	m_pLegend->ShowLegendTitle(m_bShowLegendTitle, m_strLegendName);

	Repos();
}

void CChartAdvancedLegendView::OnSize(UINT nType, int cx, int cy) 
{
	CBCGPChartExampleView::OnSize(nType, cx, cy);
	Repos();
}

void CChartAdvancedLegendView::Repos()
{
	CBCGPVisualContainer* pContainer = m_wndContainer.GetVisualContainer();
	ASSERT_VALID(pContainer);
	
	if (pContainer == NULL || pContainer->GetCount() == 0)
	{
		return;
	}
	
	ASSERT_VALID(m_pChart1);
	ASSERT_VALID(m_pChart2);
	ASSERT_VALID(m_pLegend);

	CBCGPRect rect = pContainer->GetRect();
	CBCGPRect rectLegend = rect;

	const double margin = 20.;

	CBCGPSize sizeLegend = m_pLegend->GetLegendSize();

	if (m_bIsVerticalLayout)
	{
		double dblMaxLegendWidth = 3.0 * rect.Width() / 4;

		if (sizeLegend.cx > dblMaxLegendWidth)
		{
			sizeLegend.cx = dblMaxLegendWidth;
			m_pLegend->SetAdjustLegendSizeByTitleSize(FALSE, FALSE);
		}
		else
		{
			m_pLegend->SetAdjustLegendSizeByTitleSize(TRUE, FALSE);
		}
		
		rectLegend.left = rectLegend.right - sizeLegend.cx - margin;
		rect.right = rectLegend.left;
	}
	else
	{
		rectLegend.top = rectLegend.bottom - sizeLegend.cy - margin;
		rect.bottom = rectLegend.top;
	}
	
	CBCGPRect rectChart1 = rect;
	rectChart1.SetSize(rect.Width(), rect.Height() / 2);
	
	m_pChart1->SetRect(rectChart1);
	
	CBCGPRect rectChart2 = rectChart1;
	rectChart2.OffsetRect(0, rect.Height() / 2);
	
	m_pChart2->SetRect(rectChart2);
	
	m_pLegend->SetRect(rectLegend);
	
	m_wndContainer.RedrawWindow();
}

LRESULT CChartAdvancedLegendView::OnLegendContentCreated(WPARAM, LPARAM lp)
{
	CBCGPChartLegendVisualObject* pLegend = (CBCGPChartLegendVisualObject*)lp;
	ASSERT_VALID(pLegend);

	m_pCheck1 = NULL;
	m_pRadio1 = NULL;
	m_pRadio2 = NULL;

	if (!m_bCustomEntries)
	{
		return 0;
	}

	BCGPChartCellParams params;
	params.m_brContentFill = m_brCustomCellBackground;
	params.m_brTextColor = m_brCustomCellText;
	params.SetContentPadding(CBCGPSize(10.0, 2.0));

	// Add 1-st custom entry:
	CBCGPChartLegendEntry* pEntry1 = new CBCGPChartLegendEntry(m_pLegend);
	
	CBCGPChartLegendCell* pCell = new CBCGPChartLegendCell(_T("1-st Custom Entry"));
	pCell->SetCellParams(params);

	pEntry1->AddLegendCell(pCell);

	pLegend->InsertLegendEntry(pEntry1, 0);

	// Add 2-nd custom entry:
	CBCGPChartLegendEntry* pEntry2 = new CBCGPChartLegendEntry(m_pLegend);
	pEntry2->AddLegendCell(new CBCGPChartLegendCell(_T("2-nd Custom Entry")));
	pEntry2->AddLegendCell(new CBCGPChartLegendCell(_T("Column 1")));
	pEntry2->AddLegendCell(new CBCGPChartLegendCell(_T("Column 2")));

	pLegend->AddLegendEntry(pEntry2);

	// Add 3-rd custom entry (dynamic):
	CBCGPChartLegendEntry* pEntry3 = new CBCGPChartLegendEntry(m_pLegend);

	m_pCheck1 = new CChartLegendCheckBox(this, _T("Check Box"), m_bIsChecked);
	pEntry3->AddLegendCell(m_pCheck1);

	m_pRadio1 = new CChartLegendRadioButton(this, _T("Option 1"), m_nOption == 0);
	pEntry3->AddLegendCell(m_pRadio1);

	m_pRadio2 = new CChartLegendRadioButton(this, _T("Option 2"), m_nOption == 1);
	pEntry3->AddLegendCell(m_pRadio2);

	pLegend->AddLegendEntry(pEntry3);
	return 0;
}

void CChartAdvancedLegendView::OnLegendCheckBoxClicked(CChartLegendCheckBox* pCheckBox)
{
	ASSERT_VALID(pCheckBox);

	m_bIsChecked = !m_bIsChecked;
	pCheckBox->SetSelected(m_bIsChecked);
}

void CChartAdvancedLegendView::OnLegendRadioButtonClicked(CChartLegendRadioButton* pRadioButton)
{
	ASSERT_VALID(pRadioButton);

	if (pRadioButton->IsSelected())
	{
		return;
	}

	if (m_pRadio1 != NULL)
	{
		m_pRadio1->SetSelected(FALSE);
	}

	if (m_pRadio2 != NULL)
	{
		m_pRadio2->SetSelected(FALSE);
	}

	pRadioButton->SetSelected(TRUE);

	m_nOption = (pRadioButton == m_pRadio1) ? 0 : 1;
}

void CChartAdvancedLegendView::OnChartAnimation()
{
	ASSERT_VALID(m_pChart1);
	ASSERT_VALID(m_pChart2);

	m_pChart1->StartAnimation(theApp.m_dblChartAnimationTime, theApp.m_animationType, theApp.m_animationStyle);
	m_pChart2->StartAnimation(theApp.m_dblChartAnimationTime, theApp.m_animationType, theApp.m_animationStyle);
}
